﻿/*+===================================================================
File:      GunBlock.cpp

Summary:   Định nghĩa các phương thức của CGunBlock.
===================================================================+*/

#include "GunBlock.h"
#include "Explosion.h"
#include "PlayState.h"

CGunBlock::CGunBlock(CBill* bill, D3DXVECTOR2 pos, int id, int typeId) : CMoveableObject(pos, id, typeId)
{
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_GUN_BLOCK_GUN);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_GUN_BLOCK_BASE_CLOSE);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_GUN_BLOCK_BASE_CHANGING);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_GUN_BLOCK_BASE_OPEN);
	m_bill = bill;
	m_nStatus = Status::Close;
	UpdateAnimation();
	m_pGun = new CGun(ID_ENEMY_SMALL_WHITE_BULLET, 1, 1);

	m_nLife = 10;

	m_box.width = 28;
	m_box.height = 28;
}

CGunBlock::~CGunBlock()
{
	if (m_pGunSprite)
		delete m_pGunSprite;
	if (m_pBaseSprite)
		delete m_pBaseSprite;
	if (m_pGun)
		delete m_pGun;
	if (m_bill)
		delete m_bill;
}

void CGunBlock::UpdateAnimation()
{
	switch (m_nStatus)
	{
	case Status::Close:
	case Status::CloseForever:
		m_pGunSprite = NULL;
		m_pBaseSprite = m_pResourceManager->GetSprite(ID_SPRITE_GUN_BLOCK_BASE_CLOSE);
		break;
	case Status::Changing:
		m_pBaseSprite = m_pResourceManager->GetSprite(ID_SPRITE_GUN_BLOCK_BASE_CHANGING);
		break;
	case Status::Open:
		m_pGunSprite = m_pResourceManager->GetSprite(ID_SPRITE_GUN_BLOCK_GUN);
		m_pBaseSprite = m_pResourceManager->GetSprite(ID_SPRITE_GUN_BLOCK_BASE_OPEN);
		break;
	}
}

void CGunBlock::Update(float timeFrame)
{
	if (!m_bIsLive)
		return;

	D3DXVECTOR2 billPos = m_bill->GetPos();

	if (g_nCurentLvl == ID_LEVEL2)
	{
		// Khi bill đến khoảng cách nhất định -> mở GunBlock ra.
		if (m_nStatus == Status::Close && m_pos.y - 80 < billPos.y)
		{
			m_nStatus = Status::Changing;
			m_fTimeAnimation = 0.2f;
		}

		// Khi bill xa ra 1 khoảng cách nhất định -> đóng GunBlock lại.
		if (m_nStatus == Status::Open && billPos.y > m_pos.y + 180)
		{
			m_nStatus = Status::CloseForever;
		}
	}
	else
	{
		// Khi bill đến khoảng cách nhất định -> mở GunBlock ra.
		if (m_nStatus == Status::Close && m_pos.x - 250 < billPos.x)
		{
			m_nStatus = Status::Changing;
			m_fTimeAnimation = 0.2f;
		}

		// Khi bill xa ra 1 khoảng cách nhất định -> đóng GunBlock lại.
		if (m_nStatus == Status::Open && billPos.x > m_pos.x + 250)
		{
			m_nStatus = Status::CloseForever;
		}
	}

	// Tính toán góc của bill so với vị trí của GunBlock.
	float angle = atan2(billPos.y - m_pos.y, billPos.x - m_pos.x) * 180 / PI;

	// Công thức ảo diệu tính đc góc bắn.
	// int temp = angle / góc bắn chia 2;
	// temp = (temp / 2) + temp % 2;
	// angle = temp * 180 / tổng số góc có thể bắn;
	int temp = angle / 15;
	temp = (temp / 2) + temp % 2;
	angle = temp * 180 / 6;

	//if (angle == -180)
	//{
	//	int a = 0;
	//}

	m_fFireAngle = angle;
	m_pGun->SetBulletAngle(m_fFireAngle);

	// Khi vừa mở GunBlock ra.
	if (m_nStatus == Status::Changing)
	{
		if (m_fTimeAnimation > 0)
		{
			m_fTimeAnimation -= timeFrame;
		}
		else
		{
			m_nStatus = Status::Open;
			m_fRotateAngle = m_fFireAngle;
		}
	}

	UpdateAnimation();

	if (m_nStatus == Status::Open)
	{
		if (m_fFireAngle == m_fRotateAngle)
		{
			// Tính vị trí của đạn theo góc quay.
			D3DXVECTOR2 bulletPos;
			int r = m_pGunSprite->GetHeight() / 2.0f - 4.0f;
			bulletPos.x = m_pos.x + sin((m_fRotateAngle - 90) * -1 * PI / 180) * r;
			bulletPos.y = m_pos.y + cos((m_fRotateAngle - 90) * -1 * PI / 180) * r;

			m_pGun->Fire(bulletPos);
		}
		else
		{
			if (m_fTimeRotate > 0)
				m_fTimeRotate -= timeFrame;
			else
			{
				m_fTimeRotate = 0.5f;

				// Quay gun.
				if (abs(m_fFireAngle - m_fRotateAngle) < 180)
				{
					if (m_fFireAngle > m_fRotateAngle)
						m_fRotateAngle += 30;
					else
						m_fRotateAngle -= 30;
				}
				else
				{
					// Trường hợp góc đặc biệt.
					if (m_fFireAngle < 0 && m_fRotateAngle > 0)
						m_fRotateAngle += 30;
					else if (m_fFireAngle > 0 && m_fRotateAngle < 0)
						m_fRotateAngle -= 30;
				}

				// Reset lại góc về hệ [-180, 180] nếu góc đó vượt quá.
				if (m_fRotateAngle > 180)
					m_fRotateAngle -= 360;
				else if (m_fRotateAngle < -180)
					m_fRotateAngle = 360 - abs(m_fRotateAngle);
			}
		}
	}

	UpdateBox(timeFrame);
}

void CGunBlock::UpdateCollision(vector<CGameObject*> vecGameObjs, float timeFrame)
{
	if (!m_bIsLive || m_nStatus != Status::Open)
		return;

	float timeCollision = timeFrame;
	CGameObject* objCollision = NULL; // Đối tượng va chạm sớm nhất.
	float normalx = 0.0f, normaly = 0.0f;

	// Xử lí va chạm với đạn của Bill
	for (int i = 0; i < CPlayState::s_billBullets.size(); i++)
	{
		if (CPlayState::s_billBullets[i]->IsLive())
		{
			float t = CheckCollision(CPlayState::s_billBullets[i], normalx, normaly, timeFrame);

			if (t < timeFrame && t < timeCollision)
			{
				// Tìm đối tượng và thời gian va chạm sớm nhất.
				timeCollision = t;
				objCollision = CPlayState::s_billBullets[i];
			}
		}
	}

	// Xử lí va chạm
	if (objCollision != NULL)
	{
		this->Kill();
		objCollision->Kill();
	}
}

void CGunBlock::Draw()
{
	if (!m_bIsLive)
		return;
	D3DXVECTOR2 pos = CViewport::GetInstance()->TransformMatrix(m_pos);

	m_pBaseSprite->Draw(pos);

	if (m_nStatus == Status::Open)
		// Phải tranform sang góc quay do góc được tính ra ở trên khác.
		m_pGunSprite->Draw(pos, (m_fRotateAngle - 90) * -1 * PI / 180);
}

bool CGunBlock::Kill()
{
	if (m_nStatus == Status::Open)
	{
		if (m_nLife > 1)
			m_nLife--;
		else
		{
			m_bIsLive = false;
			CExplosion* explosion = new CExplosion(m_pos, 0, ID_SMALL_EXPLOSION);
			CPlayState::s_objsOutSideQuadTree.push_back(explosion);
		}
		g_nScore += 100;
		return true;
	}

	return false;
}